from dataclasses import dataclass
from json import dumps, loads

from .my_cursor import MyCursor

DIY_PROBLEM_ID_START = 161

@dataclass
class Problem():
    map : dict
    level : int


class ProblemDatabase():
    PROBLEM_TABLE_NAME = 'problem_table'
    DIY_PROBLEM_TABLE_NAME = 'diy_problem_table'

    def __init__(self) -> None:
        self.cache_problem : dict[int, Problem] = {}
        self.cacheProblem()


    def cacheProblem(self):
        with MyCursor() as cursor:
            cursor.execute(f"""
                select problem_id, map, level from {self.PROBLEM_TABLE_NAME};
                """
            )
            rows = cursor.fetchall()

        for row in rows:
            problem_id, map_string, level = int(row[0]), str(row[1]), int(row[2])
            self.cache_problem[problem_id] = Problem(
                dict(loads(map_string)), level
            )


    def getDiyProblem(self, problem_id : int) -> dict:
        with MyCursor() as cursor:
            cursor.execute(f"""
                select (designer, description, map) from {self.DIY_PROBLEM_TABLE_NAME}
                where problem_id = {problem_id};
                """
            )
            row = cursor.fetchone()

        designer, description, map_string = str(row[0]), str(row[1]), str(row[2])

        return dict(loads(map_string))


    def GetProblem(self, problem_id : int) -> dict:
        if problem_id < DIY_PROBLEM_ID_START:
            return self.cache_problem[problem_id].map
        else:
            return self.getDiyProblem(problem_id)


    def IsProblemExists(self, problem_id : int) -> bool:
        if problem_id in self.cache_problem.keys():
            return True

        with MyCursor() as cursor:
            cursor.execute(f"""
                select count(*) from {self.DIY_PROBLEM_TABLE_NAME}
                where problem_id = {problem_id};
                """
            )
            counts = int(cursor.fetchone()[0])

        return counts != 0


    def InsertDiyProblem(self, map : dict, designer : str, description : str) -> int:
        with MyCursor() as cursor:
            cursor.execute(f"""
                insert into {self.DIY_PROBLEM_TABLE_NAME}(designer, description, map)
                values("{designer}", "{description}", '{dumps(map)}');
                """
            )
            cursor.connection.commit()

            cursor.execute("select LAST_INSERT_ID();")
            problem_id = int(cursor.fetchone()[0])

        return problem_id


db = ProblemDatabase()